home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / gnustuff / tos / othergnu / ispell.zoo / buildhash.c next >
Encoding:
C/C++ Source or Header  |  1990-04-18  |  10.3 KB  |  514 lines

  1. /* -*- Mode: Text -*- */
  2.  
  3. #define MAIN
  4.  
  5. /*
  6.  * buildhash.c - make a hash table for ispell
  7.  *
  8.  * Pace Willisson, 1983
  9.  */
  10.  
  11. #include <ctype.h>
  12. #include <stdio.h>
  13. #ifdef USG
  14. #include <sys/types.h>
  15. #endif
  16. #include <sys/param.h>
  17. #include <sys/stat.h>
  18. #include "config.h"
  19. #include "ispell.h"
  20.  
  21. #define NSTAT 100
  22. struct stat dstat, cstat;
  23.  
  24. int numwords, hashsize;
  25.  
  26. char *malloc();
  27. char *realloc ();
  28.  
  29. struct dent *hashtbl;
  30.  
  31. char *Dfile;
  32. char *Hfile;
  33.  
  34. char Cfile[MAXPATHLEN];
  35. char Sfile[MAXPATHLEN];
  36.  
  37. #ifdef atarist
  38. long _stksize = -1L;
  39. #endif
  40.  
  41. main (argc,argv)
  42. int argc;
  43. char **argv;
  44. {
  45.     FILE *countf;
  46.     FILE *statf;
  47.     int stats[NSTAT];
  48.     int i;
  49.  
  50.     if (argc > 1) {
  51.         ++argv;
  52.         Dfile = *argv;
  53.         if (argc > 2) {
  54.             ++argv;
  55.             Hfile = *argv;
  56.         }
  57.         else
  58.             Hfile = DEFHASH;
  59.     }
  60.     else {
  61.         Dfile = DEFDICT;
  62.         Hfile = DEFHASH;
  63.     }
  64.  
  65. #ifdef atarist
  66.     sprintf(Cfile,"%sct",Dfile);
  67.     sprintf(Sfile,"%sst",Dfile);
  68. #else
  69.     sprintf(Cfile,"%s.cnt",Dfile);
  70.     sprintf(Sfile,"%s.stat",Dfile);
  71. #endif
  72.  
  73.     if (stat (Dfile, &dstat) < 0) {
  74.         fprintf (stderr, "No dictionary (%s)\n", Dfile);
  75.         exit (1);
  76.     }
  77.  
  78.     if (stat (Cfile, &cstat) < 0 || dstat.st_mtime > cstat.st_mtime)
  79.         newcount ();
  80.  
  81.     if ((countf = fopen (Cfile, "r")) == NULL) {
  82.         fprintf (stderr, "No count file\n");
  83.         exit (1);
  84.     }
  85.     numwords = 0;
  86.     fscanf (countf, "%d", &numwords);
  87.     fclose (countf);
  88.     if (numwords == 0) {
  89.         fprintf (stderr, "Bad count file\n");
  90.         exit (1);
  91.     }
  92.     hashsize = numwords;
  93.     readdict ();
  94.  
  95.     if ((statf = fopen (Sfile, "w")) == NULL) {
  96.         fprintf (stderr, "Can't create %s\n", Sfile);
  97.         exit (1);
  98.     }
  99.  
  100.     for (i = 0; i < NSTAT; i++)
  101.         stats[i] = 0;
  102.     for (i = 0; i < hashsize; i++) {
  103.         struct dent *dp;
  104.         int j;
  105.         if (hashtbl[i].used == 0) {
  106.             stats[0]++;
  107.         } else {
  108.             for (j = 1, dp = &hashtbl[i]; dp->next != NULL; j++, dp = dp->next)
  109.                 ;
  110.             if (j >= NSTAT)
  111.                 j = NSTAT - 1;
  112.             stats[j]++;
  113.         }
  114.     }
  115.     for (i = 0; i < NSTAT; i++)
  116.         fprintf (statf, "%d: %d\n", i, stats[i]);
  117.     fclose (statf);
  118.  
  119.     filltable ();
  120.  
  121.     output ();
  122.     exit(0);
  123. }
  124.  
  125. output ()
  126. {
  127.     FILE *outfile;
  128.     struct hashheader hashheader;
  129.     int strptr, n, i;
  130.  
  131. #ifdef atarist
  132.     if ((outfile = fopen (Hfile, "wb")) == NULL) {
  133. #else
  134.     if ((outfile = fopen (Hfile, "w")) == NULL) {
  135. #endif
  136.         fprintf (stderr, "can't create %s\n",Hfile);
  137.         return;
  138.     }
  139.     hashheader.magic = MAGIC;
  140.     hashheader.stringsize = 0;
  141.     hashheader.tblsize = hashsize;
  142.     fwrite (&hashheader, sizeof hashheader, 1, outfile);
  143.     strptr = 0;
  144.     for (i = 0; i < hashsize; i++) {
  145.         n = strlen (hashtbl[i].word) + 1;
  146. #ifdef CAPITALIZE
  147.         if (hashtbl[i].followcase)
  148.             n += (hashtbl[i].word[n] & 0xFF) * (n + 1) + 1;
  149. #endif
  150.         fwrite (hashtbl[i].word, n, 1, outfile);
  151.         hashtbl[i].word = (char *)strptr;
  152.         strptr += n;
  153.     }
  154.     /* Pad file to a struct dent boundary for efficiency. */
  155.     n = (strptr + sizeof hashheader) % sizeof (struct dent);
  156.     if (n != 0) {
  157.         n = sizeof (struct dent) - n;
  158.         strptr += n;
  159.         while (--n >= 0)
  160.             putc ('\0', outfile);
  161.     }
  162.     for (i = 0; i < hashsize; i++) {
  163.         if (hashtbl[i].next != 0) {
  164.             int x;
  165.             x = hashtbl[i].next - hashtbl;
  166.             hashtbl[i].next = (struct dent *)x;
  167.         } else {
  168.             hashtbl[i].next = (struct dent *)-1;
  169.         }
  170.     }
  171.     fwrite (hashtbl, sizeof (struct dent), hashsize, outfile);
  172.     hashheader.stringsize = strptr;
  173.     rewind (outfile);
  174.     fwrite (&hashheader, sizeof hashheader, 1, outfile);
  175.     fclose (outfile);
  176. }
  177.  
  178. filltable ()
  179. {
  180.     struct dent *freepointer, *nextword, *dp;
  181.     int i;
  182.  
  183.     for (freepointer = hashtbl; freepointer->used; freepointer++)
  184.         ;
  185.     for (nextword = hashtbl, i = numwords; i != 0; nextword++, i--) {
  186.         if (nextword->used == 0) {
  187.             continue;
  188.         }
  189.         if (nextword->next == NULL) {
  190.             continue;
  191.         }
  192.         if (nextword->next >= hashtbl && nextword->next < hashtbl + hashsize) {
  193.             continue;
  194.         }
  195.         dp = nextword;
  196.         while (dp->next) {
  197.             if (freepointer > hashtbl + hashsize) {
  198.                 fprintf (stderr, "table overflow\n");
  199.                 getchar ();
  200.                 break;
  201.             }
  202.             *freepointer = *(dp->next);
  203.             dp->next = freepointer;
  204.             dp = freepointer;
  205.  
  206.             while (freepointer->used)
  207.                 freepointer++;
  208.         }
  209.     }
  210. }
  211.  
  212.  
  213. readdict ()
  214. {
  215.     struct dent d;
  216.     register struct dent *dp;
  217.     char lbuf[100];
  218.     FILE *dictf;
  219.     int i;
  220.     int h;
  221.     int len;
  222.     register char *p;
  223.  
  224.     if ((dictf = fopen (Dfile, "r")) == NULL) {
  225.         fprintf (stderr, "Can't open dictionary\n");
  226.         exit (1);
  227.     }
  228.  
  229.     hashtbl = (struct dent *) calloc (numwords, sizeof (struct dent));
  230.     if (hashtbl == NULL) {
  231.         fprintf (stderr, "couldn't allocate hash table\n");
  232.         exit (1);
  233.     }
  234.  
  235.     i = 0;
  236.     while (fgets (lbuf, sizeof lbuf, dictf) != NULL) {
  237.         if ((i & 1023) == 0) {
  238.             printf ("%d ", i);
  239.             fflush (stdout);
  240.         }
  241.         i++;
  242.  
  243.         p = &lbuf [ strlen (lbuf) - 1 ];
  244.         if (*p == '\n')
  245.             *p = 0;
  246.  
  247.         if (makedent (lbuf, &d) < 0)
  248.             continue;
  249.  
  250.         len = strlen (lbuf);
  251. #ifdef CAPITALIZE
  252.         if (d.followcase)
  253.             d.word = malloc (2 * len + 4);
  254.         else
  255.             d.word = malloc (len + 1);
  256. #else
  257.         d.word = malloc (len + 1);
  258. #endif
  259.         if (d.word == NULL) {
  260.             fprintf (stderr, "couldn't allocate space for word %s\n", lbuf);
  261.             exit (1);
  262.         }
  263.         strcpy (d.word, lbuf);
  264. #ifdef CAPITALIZE
  265.         if (d.followcase) {
  266.             p = d.word + len + 1;
  267.             *p++ = 1;        /* Count of capitalizations */
  268.             *p++ = '-';        /* Don't keep in pers dict */
  269.             strcpy (p, lbuf);
  270.             
  271.         }
  272.         for (p = d.word;  *p;  p++) {
  273.             if (mylower (*p))
  274.                 *p = toupper (*p);
  275.         }
  276. #endif
  277.  
  278.         h = hash (d.word, len, hashsize);
  279.  
  280.         dp = &hashtbl[h];
  281.         if (dp->used == 0) {
  282.             *dp = d;
  283.         } else {
  284.  
  285. #ifdef CAPITALIZE
  286.             while (dp != NULL  &&  strcmp (dp->word, d.word) != 0)
  287.                 dp = dp->next;
  288.             if (dp != NULL) {
  289.                 if (d.followcase
  290.                   ||  (dp->followcase  &&  !d.allcaps
  291.                 &&  !d.capitalize)) {
  292.                 /* Add a specific capitalization */
  293.                 if (dp->followcase) {
  294.                     p = &dp->word[len + 1];
  295.                     (*p)++;    /* Bump counter */
  296.                     dp->word = realloc (dp->word,
  297.                       ((*p & 0xFF) + 1) * (len + 2));
  298.                     if (dp->word == NULL) {
  299.                     fprintf (stderr,
  300.                       "couldn't allocate space for word %s\n",
  301.                       lbuf);
  302.                     exit (1);
  303.                     }
  304.                     p = &dp->word[len + 1];
  305.                     p += ((*p & 0xFF) - 1) * (len + 2) + 1;
  306.                     *p++ = '-';
  307.                     strcpy (p,
  308.                       d.followcase ? &d.word[len + 3] : lbuf);
  309.                 }
  310.                 else {
  311.                     /* d.followcase must be true */
  312.                     /* thus, d.capitalize and d.allcaps are */
  313.                     /* clear */
  314.                     free (dp->word);
  315.                     dp->word = d.word;
  316.                     dp->followcase = 1;
  317.                     dp->k_followcase = 1;
  318.                     /* Code later will clear dp->allcaps. */
  319.                 }
  320.                 }
  321.                 /* Combine two capitalizations.  If d was */
  322.                 /* allcaps, dp remains unchanged */
  323.                 if (d.allcaps == 0) {
  324.                 /* dp is the entry that will be kept.  If */
  325.                 /* dp is followcase, the capitalize flag */
  326.                 /* reflects whether capitalization "may" */
  327.                 /* occur.  If not, it reflects whether it */
  328.                 /* "must" occur. */
  329.                 if (d.capitalize) {    /* ie lbuf was cap'd */
  330.                     if (dp->followcase)
  331.                     dp->capitalize = 1;    /* May */
  332.                     else if (dp->allcaps) /* ie not lcase */
  333.                     dp->capitalize = 1;    /* Must */
  334.                 }
  335.                 else {        /* lbuf was followc or all-lc */
  336.                     if (!dp->followcase)
  337.                     dp->capitalize == 0;    /* May */
  338.                 }
  339.                 dp->k_capitalize == dp->capitalize;
  340.                 dp->allcaps = 0;
  341.                 dp->k_allcaps = 0;
  342.                 }
  343.             }
  344.             else {
  345. #endif
  346.                 dp = (struct dent *) malloc (sizeof (struct dent));
  347.                 if (dp == NULL) {
  348.                 fprintf (stderr,
  349.                   "couldn't allocate space for collision\n");
  350.                 exit (1);
  351.                 }
  352.                 *dp = d;
  353.                 dp->next = hashtbl[h].next;
  354.                 hashtbl[h].next = dp;
  355.             }
  356.         }
  357. #ifdef CAPITALIZE
  358.     }
  359. #endif
  360.     printf ("\n");
  361. }
  362.  
  363. /*
  364.  * fill in the flags in d, and put a null after the word in s
  365.  */
  366.  
  367. makedent (lbuf, d)
  368. char *lbuf;
  369. struct dent *d;
  370. {
  371.     char *p, *index();
  372.  
  373.     d->next = NULL;
  374.     d->used = 1;
  375.     d->v_flag = 0;
  376.     d->n_flag = 0;
  377.     d->x_flag = 0;
  378.     d->h_flag = 0;
  379.     d->y_flag = 0;
  380.     d->g_flag = 0;
  381.     d->j_flag = 0;
  382.     d->d_flag = 0;
  383.     d->t_flag = 0;
  384.     d->r_flag = 0;
  385.     d->z_flag = 0;
  386.     d->s_flag = 0;
  387.     d->p_flag = 0;
  388.     d->m_flag = 0;
  389.     d->keep = 0;
  390. #ifdef CAPITALIZE
  391.     d->allcaps = 0;
  392.     d->capitalize = 0;
  393.     d->followcase = 0;
  394.     /*
  395.     ** Figure out the capitalization rules from the capitalization of
  396.     ** the sample entry.  Only one of followcase, allcaps, and capitalize
  397.     ** will be set.  Combinations are generated by higher-level code.
  398.     */
  399.     for (p = lbuf;  *p  &&  *p != '/';  p++) {
  400.         if (mylower (*p))
  401.             break;
  402.     }
  403.     if (*p == '\0'  ||  *p == '/')
  404.         d->allcaps = 1;
  405.     else {
  406.         for (  ;  *p  &&  *p != '/';  p++) {
  407.             if (myupper (*p))
  408.                 break;
  409.         }
  410.         if (*p == '\0'  ||  *p == '/') {
  411.             /*
  412.             ** No uppercase letters follow the lowercase ones.
  413.             ** If the first two letters are capitalized, it's
  414.             ** "followcase". If the first one is capitalized, it's
  415.             ** "capitalize".
  416.             */
  417.             if (myupper (lbuf[0])) {
  418.                 if (myupper (lbuf[1]))
  419.                     d->followcase = 1;
  420.                 else
  421.                     d->capitalize = 1;
  422.             }
  423.         }
  424.         else
  425.             d->followcase = 1;    /* .../lower/upper */
  426.     }
  427.     d->k_allcaps = d->allcaps ;
  428.     d->k_capitalize = d->capitalize;
  429.     d->k_followcase = d->followcase;
  430. #endif
  431.  
  432.     p = index (lbuf, '/');
  433.     if (p != NULL)
  434.         *p = 0;
  435.     if (strlen (lbuf) > WORDLEN - 1) {
  436.         printf ("%s: word too big\n", lbuf);
  437.         return (-1);
  438.     }
  439.  
  440.     if (p == NULL)
  441.         return (0);
  442.  
  443.     p++;
  444.     while (*p != '\0'  &&  *p != '\n') {
  445.         if (mylower (*p))
  446.             *p = toupper (*p);
  447.         switch (*p) {
  448.         case 'V': d->v_flag = 1; break;
  449.         case 'N': d->n_flag = 1; break;
  450.         case 'X': d->x_flag = 1; break;
  451.         case 'H': d->h_flag = 1; break;
  452.         case 'Y': d->y_flag = 1; break;
  453.         case 'G': d->g_flag = 1; break;
  454.         case 'J': d->j_flag = 1; break;
  455.         case 'D': d->d_flag = 1; break;
  456.         case 'T': d->t_flag = 1; break;
  457.         case 'R': d->r_flag = 1; break;
  458.         case 'Z': d->z_flag = 1; break;
  459.         case 'S': d->s_flag = 1; break;
  460.         case 'P': d->p_flag = 1; break;
  461.         case 'M': d->m_flag = 1; break;
  462.         case 0:
  463.              fprintf (stderr, "no flags on word %s\n", lbuf);
  464.             continue;
  465.         default:
  466.             fprintf (stderr, "unknown flag %c word %s\n", 
  467.                     *p, lbuf);
  468.             break;
  469.         }
  470.         p++;
  471.         if (*p == '/')        /* Handle old-format dictionaries too */
  472.             p++;
  473.     }
  474.     return (0);
  475. }
  476.  
  477. newcount ()
  478. {
  479.     char buf[200];
  480.     char lastbuf[200];
  481.     FILE *d;
  482.     int i;
  483.     register char *cp;
  484.  
  485.     fprintf (stderr, "Counting words in dictionary ...\n");
  486.  
  487.     if ((d = fopen (Dfile, "r")) == NULL) {
  488.         fprintf (stderr, "Can't open dictionary\n");
  489.         exit (1);
  490.     }
  491.  
  492.     for (i = 0, lastbuf[0] = '\0';  fgets (buf, sizeof buf, d);  ) {
  493.         for (cp = buf;  *cp;  cp++) {
  494.             if (mylower (*cp))
  495.                 *cp = toupper (*cp);
  496.         }
  497.         if (strcmp (buf, lastbuf) != 0) {
  498.             if ((++i & 1023) == 0) {
  499.                 printf ("%d ", i);
  500.                 fflush (stdout);
  501.             }
  502.             strcpy (lastbuf, buf);
  503.         }
  504.     }
  505.     fclose (d);
  506.     printf ("\n%d words\n", i);
  507.     if ((d = fopen (Cfile, "w")) == NULL) {
  508.         fprintf (stderr, "can't create %s\n", Cfile);
  509.         exit (1);
  510.     }
  511.     fprintf (d, "%d\n", i);
  512.     fclose (d);
  513. }
  514.